<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/ice.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/ice.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"yoursite.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":3,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="参考文档：   Java8-Stream API 详解   java8 stream常用方法  简介Stream 作为 Java 8 的一大亮点，它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。 Java 8 中的 Stream 是对集合（Collection）对象功能的增强，它专注于对集合对象进行各种非常便利、高效的聚合操作（aggre">
<meta property="og:type" content="article">
<meta property="og:title" content="JavaStream">
<meta property="og:url" content="http://yoursite.com/2020/05/30/Java%E5%9F%BA%E7%A1%80/JavaStream/index.html">
<meta property="og:site_name" content="严冰的博客">
<meta property="og:description" content="参考文档：   Java8-Stream API 详解   java8 stream常用方法  简介Stream 作为 Java 8 的一大亮点，它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。 Java 8 中的 Stream 是对集合（Collection）对象功能的增强，它专注于对集合对象进行各种非常便利、高效的聚合操作（aggre">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-05-30T12:50:49.000Z">
<meta property="article:modified_time" content="2020-06-08T00:53:20.127Z">
<meta property="article:author" content="yanbing">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="http://yoursite.com/2020/05/30/Java%E5%9F%BA%E7%A1%80/JavaStream/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>JavaStream | 严冰的博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="严冰的博客" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">严冰的博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/05/30/Java%E5%9F%BA%E7%A1%80/JavaStream/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/dog.jpg">
      <meta itemprop="name" content="yanbing">
      <meta itemprop="description" content="闲看庭前花开落，漫随天外云卷舒。">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="严冰的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          JavaStream
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-05-30 20:50:49" itemprop="dateCreated datePublished" datetime="2020-05-30T20:50:49+08:00">2020-05-30</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2020-06-08 08:53:20" itemprop="dateModified" datetime="2020-06-08T08:53:20+08:00">2020-06-08</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <blockquote>
<p>  参考文档：</p>
<p>  <a href="https://blog.csdn.net/ycj_xiyang/article/details/83624642" target="_blank" rel="noopener">Java8-Stream API 详解</a></p>
<p>  <a href="https://blog.csdn.net/zxl646801924/article/details/90374320?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase" target="_blank" rel="noopener">java8 stream常用方法</a></p>
</blockquote>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>Stream 作为 Java 8 的一大亮点，它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。</p>
<p>Java 8 中的 <strong>Stream 是对集合（Collection）对象功能的增强</strong>，它专注于对集合对象进行各种非常便利、高效的聚合操作（aggregate operation），或者大批量数据操作 (bulk data operation)。</p>
<p>Stream API 借助于同样新出现的 Lambda 表达式，极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作，并发模式能够充分利用多核处理器的优势，使用 fork/join 并行方式来拆分任务和加速处理过程。</p>
<p>通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码，就可以很方便地写出高性能的并发程序。</p>
<p>所以说，Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。</p>
<a id="more"></a>

<h2 id="Stream的概念"><a href="#Stream的概念" class="headerlink" title="Stream的概念"></a>Stream的概念</h2><p>流（Stream）是数据通道，用于操作数据源（集合，数组等）所生成的元素序列。整个流操作就是一条流水线，将元素放在流水线上一个个地进行处理。</p>
<p><strong>集合讲的的是数据，流讲的是计算。</strong></p>
<p>其中数据源便是原始集合，然后将如 <code>List&lt;T&gt;</code> 的集合转换为 <code>Stream&lt;T&gt;</code> 类型的流，并对流进行一系列的中间操作，比如过滤保留部分元素、对元素进行排序、类型转换等；最后再进行一个终端操作，可以把 Stream 转换回集合类型，也可以直接对其中的各个元素进行处理，比如打印、比如计算总数、计算最大值等等。</p>
<p>很重要的一点是，很多流操作本身就会返回一个流，所以多个操作可以直接连接起来。如果是以前，进行这么一系列操作，你需要做个迭代器或者 foreach 循环，然后遍历，一步步地地去完成这些操作；但是如果使用流，你便可以直接声明式地下指令，流会帮你完成这些操作。</p>
<p>注意：</p>
<ol>
<li>Stream不会存储元素</li>
<li>Stream不会改变源对象，相反他们会返回一个持有结果的新的Stream</li>
<li>Stream操作是延迟执行的，这意味着他们等到需要结果的时候才会执行（惰性求值）</li>
</ol>
<h2 id="Stream操作的三个步骤"><a href="#Stream操作的三个步骤" class="headerlink" title="Stream操作的三个步骤"></a>Stream操作的三个步骤</h2><ol>
<li><p>创建</p>
<p>一个数据源（如：集合，数组）获取一个流</p>
</li>
<li><p>中间操作</p>
<p>一个中间操作链，对数据源的数据进行处理</p>
</li>
<li><p>终止操作（终端操作）</p>
<p>一个终止操作，执行中间操作链，并产生结果</p>
</li>
</ol>
<h2 id="创建Stream"><a href="#创建Stream" class="headerlink" title="创建Stream"></a>创建Stream</h2><ol>
<li><code>Collection</code>提供了两个方法<code>stream()</code>与<code>paralleStream()</code></li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">Stream&lt;Integer&gt; stream = list.stream();<span class="comment">//串行流</span></span><br><span class="line">Stream&lt;Integer&gt; integerStream = list.parallelStream();<span class="comment">//并行流</span></span><br></pre></td></tr></table></figure>

<ol start="2">
<li>通过<code>Arrays</code>中的<code>Stream()</code>获取一个数组流。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Integer[] integers =&#123;&#125;;</span><br><span class="line">Stream&lt;Integer&gt; stream = Arrays.stream(integers);</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>通过<code>Stream</code>类中静态方法<code>of()</code></li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Stream&lt;String&gt; stream = Stream.of(<span class="string">"aaa"</span>, <span class="string">"bbb"</span>);</span><br></pre></td></tr></table></figure>

<h2 id="常用方法"><a href="#常用方法" class="headerlink" title="常用方法"></a>常用方法</h2><h3 id="filter-T-gt-boolean"><a href="#filter-T-gt-boolean" class="headerlink" title="filter(T -&gt; boolean)"></a>filter(T -&gt; boolean)</h3><p>保留 boolean 为 true 的元素</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//保留年龄为 20 的 person 元素</span></span><br><span class="line">list = list.stream()</span><br><span class="line">            .filter(person -&gt; person.getAge() == <span class="number">20</span>)</span><br><span class="line">            .collect(toList());	<span class="comment">//collect(toList()) 可以把流转换为 List 类型</span></span><br><span class="line"><span class="comment">//打印输出 [Person&#123;name='jack', age=20&#125;]</span></span><br></pre></td></tr></table></figure>

<h3 id="distinct"><a href="#distinct" class="headerlink" title="distinct()"></a>distinct()</h3><p>去除重复元素，这个方法是通过类的 <code>equals</code> 方法来判断两个元素是否相等的。</p>
<p>如例子中的 Person 类，需要先定义好 equals 方法，不然类似<code>[Person{name=&#39;jack&#39;, age=20}, Person{name=&#39;jack&#39;, age=20}]</code>这样的情况是不会处理的。</p>
<h3 id="sorted-sorted-T-T-gt-int"><a href="#sorted-sorted-T-T-gt-int" class="headerlink" title="sorted() / sorted((T, T) -&gt; int)"></a>sorted() / sorted((T, T) -&gt; int)</h3><p>如果流中的元素的类实现了 <code>Comparable</code> 接口，即有自己的排序规则，那么可以直接调用 <code>sorted()</code> 方法对元素进行排序。</p>
<p>反之, 需要调用 <code>sorted((T, T) -&gt; int)</code> 实现 <code>Comparator</code> 接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//根据年龄大小来比较：</span></span><br><span class="line">list = list.stream()</span><br><span class="line">           .sorted((p1, p2) -&gt; p1.getAge() - p2.getAge())</span><br><span class="line">           .collect(toList());</span><br></pre></td></tr></table></figure>

<p>简化：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">list = list.stream()</span><br><span class="line">           .sorted(Comparator.comparingInt(Person::getAge))</span><br><span class="line">           .collect(toList());</span><br></pre></td></tr></table></figure>

<h3 id="limit-long-n"><a href="#limit-long-n" class="headerlink" title="limit(long n)"></a>limit(long n)</h3><p>返回前 n 个元素</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">list = list.stream()</span><br><span class="line">            .limit(<span class="number">2</span>)</span><br><span class="line">            .collect(toList());</span><br><span class="line"> </span><br><span class="line"><span class="comment">//打印输出 [Person&#123;name='jack', age=20&#125;, Person&#123;name='mike', age=25&#125;]</span></span><br></pre></td></tr></table></figure>

<h3 id="skip-long-n"><a href="#skip-long-n" class="headerlink" title="skip(long n)"></a>skip(long n)</h3><p>去除前 n 个元素</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">list = list.stream()</span><br><span class="line">            .skip(<span class="number">2</span>)</span><br><span class="line">            .collect(toList());</span><br><span class="line"> </span><br><span class="line"><span class="comment">//打印输出 [Person&#123;name='tom', age=30&#125;]</span></span><br></pre></td></tr></table></figure>

<ul>
<li><code>skip(n)</code>用在 <code>limit(n)</code> 前面时，先去除前 m 个元素再返回剩余元素的前 n 个元素</li>
<li><code>limit(n)</code> 用在 <code>skip(m)</code> 前面时，先返回前 n 个元素再在剩余的 n 个元素中去除 m 个元素</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">list = list.stream()</span><br><span class="line">            .limit(<span class="number">2</span>)</span><br><span class="line">            .skip(<span class="number">1</span>)</span><br><span class="line">            .collect(toList());</span><br><span class="line"> </span><br><span class="line"><span class="comment">//打印输出 [Person&#123;name='mike', age=25&#125;]</span></span><br></pre></td></tr></table></figure>

<h3 id="map-T-gt-R"><a href="#map-T-gt-R" class="headerlink" title="map(T -&gt; R)"></a>map(T -&gt; R)</h3><p>将流中的每一个元素 T 映射为 R（类似类型转换）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; newlist = list.stream()</span><br><span class="line">    						.map(Person::getName)</span><br><span class="line">    						.collect(toList());</span><br><span class="line"><span class="comment">//newlist 里面的元素为 list 中每一个 Person 对象的 name 变量</span></span><br></pre></td></tr></table></figure>

<h3 id="flatMap-T-gt-Stream"><a href="#flatMap-T-gt-Stream" class="headerlink" title="flatMap(T -&gt; Stream)"></a>flatMap(T -&gt; Stream)</h3><p>将流中的每一个元素 T 映射为一个流，再把每一个流连接成为一个流</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"aaa bbb ccc"</span>);</span><br><span class="line">list.add(<span class="string">"ddd eee fff"</span>);</span><br><span class="line">list.add(<span class="string">"ggg hhh iii"</span>);</span><br><span class="line"> </span><br><span class="line">list = list.stream()</span><br><span class="line">    .map(s -&gt; s.split(<span class="string">" "</span>))</span><br><span class="line">    .flatMap(Arrays::stream)</span><br><span class="line">    .collect(toList());</span><br></pre></td></tr></table></figure>

<p>我们的目的是把 List 中每个字符串元素以” “分割开，变成一个新的 List。</p>
<p>首先 map 方法分割每个字符串元素，但此时流的类型为 Stream&lt;String[ ]&gt;，因为 split 方法返回的是 String[ ] 类型；所以我们需要使用 flatMap 方法，先使用Arrays::stream将每个 String[ ] 元素变成一个 Stream 流，然后 flatMap 会将每一个流连接成为一个流，最终返回我们需要的 Stream。</p>
<h3 id="anyMatch-T-gt-boolean"><a href="#anyMatch-T-gt-boolean" class="headerlink" title="anyMatch(T -&gt; boolean)"></a>anyMatch(T -&gt; boolean)</h3><p>流中是否有一个元素匹配给定的 <code>T -&gt; boolean</code> 条件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//是否存在一个 person 对象的 age 等于 20：</span></span><br><span class="line"><span class="keyword">boolean</span> b = list.stream()</span><br><span class="line">    .anyMatch(person -&gt; person.getAge() == <span class="number">20</span>);</span><br></pre></td></tr></table></figure>

<h3 id="allMatch-T-gt-boolean"><a href="#allMatch-T-gt-boolean" class="headerlink" title="allMatch(T -&gt; boolean)"></a>allMatch(T -&gt; boolean)</h3><p>流中是否所有元素都匹配给定的 <code>T -&gt; boolean</code> 条件</p>
<h3 id="noneMatch-T-gt-boolean"><a href="#noneMatch-T-gt-boolean" class="headerlink" title="noneMatch(T -&gt; boolean)"></a>noneMatch(T -&gt; boolean)</h3><p>流中是否没有元素匹配给定的 T -&gt; boolean 条件</p>
<h3 id="findAny-和-findFirst"><a href="#findAny-和-findFirst" class="headerlink" title="findAny() 和 findFirst()"></a>findAny() 和 findFirst()</h3><ul>
<li><p>findAny()：找到其中一个元素 （使用 stream() 时找到的是第一个元素；使用 parallelStream() 并行时找到的是其中一个元素）</p>
</li>
<li><p>findFirst()：找到第一个元素</p>
</li>
</ul>
<p>值得注意的是，这两个方法返回的是一个 Optional 对象，它是一个容器类，能代表一个值存在或不存在</p>
<h3 id="reduce-T-T-gt-T-和-reduce-T-T-T-gt-T"><a href="#reduce-T-T-gt-T-和-reduce-T-T-T-gt-T" class="headerlink" title="reduce((T, T) -&gt; T) 和 reduce(T, (T, T) -&gt; T)"></a>reduce((T, T) -&gt; T) 和 reduce(T, (T, T) -&gt; T)</h3><p>用于组合流中的元素，如求和，求积，求最大值等</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//计算年龄总和：</span></span><br><span class="line"><span class="keyword">int</span> sum = list.stream()</span><br><span class="line">    .map(Person::getAge)</span><br><span class="line">    .reduce(<span class="number">0</span>, (a, b) -&gt; a + b);</span><br><span class="line"><span class="comment">//与之相同:</span></span><br><span class="line"><span class="keyword">int</span> sum = list.stream()</span><br><span class="line">    .map(Person::getAge)</span><br><span class="line">    .reduce(<span class="number">0</span>, Integer::sum);</span><br><span class="line"><span class="comment">//其中，reduce 第一个参数 0 代表起始值为 0，lambda (a, b) -&gt; a + b 即将两值相加产生一个新值</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//计算年龄总乘积：</span></span><br><span class="line"><span class="keyword">int</span> sum = list.stream()</span><br><span class="line">    .map(Person::getAge)</span><br><span class="line">    .reduce(<span class="number">1</span>, (a, b) -&gt; a * b);</span><br><span class="line"><span class="comment">//与之相同:</span></span><br><span class="line">Optional&lt;Integer&gt; sum = list.stream()</span><br><span class="line">    .map(Person::getAge)</span><br><span class="line">    .reduce(Integer::sum);</span><br><span class="line"><span class="comment">//不接受任何起始值，但因为没有初始值，需要考虑结果可能不存在的情况，因此返回的是 Optional 类型</span></span><br></pre></td></tr></table></figure>

<h3 id="count"><a href="#count" class="headerlink" title="count()"></a>count()</h3><p>返回流中元素个数，结果为 long 类型</p>
<h3 id="collect"><a href="#collect" class="headerlink" title="collect()"></a>collect()</h3><p>收集方法，我们很常用的是 <code>collect(toList())</code>，当然还有 <code>collect(toSet())</code> 等，参数是一个收集器接口</p>
<h3 id="forEach"><a href="#forEach" class="headerlink" title="forEach()"></a>forEach()</h3><p>返回结果为 void，很明显我们可以通过它来干什么了，比方说：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//打印各个元素：</span></span><br><span class="line">list.stream()</span><br><span class="line">    .forEach(System.out::println);</span><br></pre></td></tr></table></figure>

<h3 id="unordered"><a href="#unordered" class="headerlink" title="unordered()"></a>unordered()</h3><p>还有这个比较不起眼的方法，返回一个等效的无序流，当然如果流本身就是无序的话，那可能就会直接返回其本身</p>
<h2 id="数值流"><a href="#数值流" class="headerlink" title="数值流"></a>数值流</h2><p>前面介绍的如<code>int sum = list.stream().map(Person::getAge).reduce(0, Integer::sum);</code> 计算元素总和的方法，其中暗含了装箱成本，<code>map(Person::getAge)</code> 方法过后流变成了 <code>Stream</code> 类型，而每个 <code>Integer</code> 都要拆箱成一个原始类型再进行 <code>sum</code> 方法求和，这样大大影响了效率。</p>
<p>针对这个问题 Java 8 有良心地引入了数值流 <code>IntStream</code>, <code>DoubleStream</code>, <code>LongStream</code>，这种流中的元素都是原始数据类型，分别是 <code>int</code>，<code>double</code>，<code>long</code></p>
<h3 id="流与数值流的转换"><a href="#流与数值流的转换" class="headerlink" title="流与数值流的转换"></a>流与数值流的转换</h3><h4 id="流转换为数值流"><a href="#流转换为数值流" class="headerlink" title="流转换为数值流"></a>流转换为数值流</h4><ul>
<li>mapToInt(T -&gt; int) : return IntStream</li>
<li>mapToDouble(T -&gt; double) : return DoubleStream</li>
<li>mapToLong(T -&gt; long) : return LongStream</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">IntStream intStream = list.stream()</span><br><span class="line">    .mapToInt(Person::getAge);</span><br></pre></td></tr></table></figure>

<h4 id="数值流转换为流"><a href="#数值流转换为流" class="headerlink" title="数值流转换为流"></a>数值流转换为流</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Stream&lt;Integer&gt; stream = intStream.boxed();</span><br></pre></td></tr></table></figure>

<h3 id="数值流方法"><a href="#数值流方法" class="headerlink" title="数值流方法"></a>数值流方法</h3><ul>
<li>sum()</li>
<li>max()</li>
<li>min()</li>
<li>average() </li>
</ul>
<h3 id="数值范围"><a href="#数值范围" class="headerlink" title="数值范围"></a>数值范围</h3><p>IntStream 与 LongStream 拥有 range 和 rangeClosed 方法用于数值范围处理</p>
<ul>
<li><p>IntStream ： rangeClosed(int, int) / range(int, int)</p>
</li>
<li><p>LongStream ： rangeClosed(long, long) / range(long, long)</p>
</li>
</ul>
<p>我们可以利用 IntStream.rangeClosed(1, 100) 生成 1 到 100 的数值流</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//求 1 到 10 的数值总和：</span></span><br><span class="line">IntStream intStream = IntStream.rangeClosed(<span class="number">1</span>, <span class="number">10</span>);</span><br><span class="line"><span class="keyword">int</span> sum = intStream.sum();</span><br></pre></td></tr></table></figure>

<p>这两个方法的区别在于一个是闭区间，一个是半开半闭区间：</p>
<ul>
<li>rangeClosed(1, 100) ：[1, 100]</li>
<li>range(1, 100) ：[1, 100)</li>
</ul>
<h3 id="汇总"><a href="#汇总" class="headerlink" title="汇总"></a>汇总</h3><h4 id="counting"><a href="#counting" class="headerlink" title="counting"></a>counting</h4><p>用于计算总和：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">long</span> l = list.stream().collect(counting());</span><br><span class="line"><span class="comment">//推荐</span></span><br><span class="line"><span class="keyword">long</span> l = list.stream().count();</span><br></pre></td></tr></table></figure>

<h4 id="summingInt-summingLong-summingDouble"><a href="#summingInt-summingLong-summingDouble" class="headerlink" title="summingInt, summingLong, summingDouble"></a>summingInt, summingLong, summingDouble</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> sum = list.stream().collect(summingInt(Person::getAge));</span><br><span class="line"><span class="comment">//推荐</span></span><br><span class="line"><span class="keyword">int</span> sum = list.stream().mapToInt(Person::getAge).sum();</span><br><span class="line"><span class="keyword">int</span> sum = list.stream().map(Person::getAge).reduce(Interger::sum).get();</span><br></pre></td></tr></table></figure>

<h4 id="averagingInt，averagingLong，averagingDouble"><a href="#averagingInt，averagingLong，averagingDouble" class="headerlink" title="averagingInt，averagingLong，averagingDouble"></a>averagingInt，averagingLong，averagingDouble</h4><p>求平均数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Double average = list.stream().collect(averagingInt(Person::getAge));</span><br><span class="line"></span><br><span class="line">OptionalDouble average = list.stream().mapToInt(Person::getAge).average();</span><br></pre></td></tr></table></figure>

<h4 id="summarizingInt，summarizingLong，summarizingDouble"><a href="#summarizingInt，summarizingLong，summarizingDouble" class="headerlink" title="summarizingInt，summarizingLong，summarizingDouble"></a>summarizingInt，summarizingLong，summarizingDouble</h4><p>这三个方法比较特殊，比如 summarizingInt 会返回 IntSummaryStatistics 类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IntSummaryStatistics l = list.stream().collect(summarizingInt(Person::getAge));</span><br></pre></td></tr></table></figure>

<p>IntSummaryStatistics 包含了计算出来的平均值，总数，总和，最值，可以通过下面这些方法获得相应的数据</p>
<ul>
<li>getAverage()</li>
<li>getCount()</li>
<li>getMax()</li>
<li>getMin()</li>
<li>getSum()</li>
</ul>
<h3 id="取最值"><a href="#取最值" class="headerlink" title="取最值"></a>取最值</h3><p>maxBy，minBy 两个方法，需要一个 Comparator 接口作为参数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Optional&lt;Person&gt; optional = list.stream().collect(maxBy(comparing(Person::getAge)));</span><br><span class="line">Optional&lt;Person&gt; optional = list.stream().max(comparing(Person::getAge));</span><br></pre></td></tr></table></figure>

<h3 id="joining-连接字符串"><a href="#joining-连接字符串" class="headerlink" title="joining 连接字符串"></a>joining 连接字符串</h3><p>对流里面的字符串元素进行连接，<strong>其底层实现用的是专门用于字符串连接的 StringBuilder</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">String s = list.stream().map(Person::getName).collect(joining());</span><br><span class="line"><span class="comment">//结果：jackmiketom</span></span><br><span class="line">String s = list.stream().map(Person::getName).collect(joining(<span class="string">","</span>));</span><br><span class="line"><span class="comment">//结果：jack,mike,tom</span></span><br><span class="line">String s = list.stream().map(Person::getName).collect(joining(<span class="string">" and "</span>, <span class="string">"Today "</span>, <span class="string">" play games."</span>));</span><br><span class="line"><span class="comment">//结果：Today jack and mike and tom play games</span></span><br><span class="line"><span class="comment">//即 Today 放开头，play games. 放结尾，and 在中间连接各个字符串</span></span><br></pre></td></tr></table></figure>

<h3 id="groupingBy-分组"><a href="#groupingBy-分组" class="headerlink" title="groupingBy 分组"></a>groupingBy 分组</h3><p>groupingBy 用于将数据分组，最终返回一个 Map 类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;Integer, List&lt;Person&gt;&gt; map = list.stream().collect(groupingBy(Person::getAge));</span><br><span class="line"><span class="comment">//按照年龄 age 分组，每一个 Person 对象中年龄相同的归为一组</span></span><br><span class="line"><span class="comment">//Person::getAge 决定 Map 的键（Integer 类型），list 类型决定 Map 的值（List 类型）</span></span><br></pre></td></tr></table></figure>

<h3 id="partitioningBy-分区"><a href="#partitioningBy-分区" class="headerlink" title="partitioningBy 分区"></a>partitioningBy 分区</h3><p>分区与分组的区别在于，分区是按照 true 和 false 来分的，因此partitioningBy 接受的参数的 lambda 也是 <code>T -&gt; boolean</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//根据年龄是否小于等于20来分区</span></span><br><span class="line">Map&lt;Boolean, List&lt;Person&gt;&gt; map = list.stream()</span><br><span class="line">                                     .collect(partitioningBy(p -&gt; p.getAge() &lt;= <span class="number">20</span>));</span><br><span class="line"><span class="comment">//打印输出</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">false</span>=[Person&#123;name=<span class="string">'mike'</span>, age=<span class="number">25</span>&#125;, Person&#123;name=<span class="string">'tom'</span>, age=<span class="number">30</span>&#125;], </span><br><span class="line">    <span class="keyword">true</span>=[Person&#123;name=<span class="string">'jack'</span>, age=<span class="number">20</span>&#125;]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="并行"><a href="#并行" class="headerlink" title="并行"></a>并行</h2><p>之前我就讲到了 parallelStream 方法能生成并行流，因此你通常可以使用 parallelStream 来代替 stream 方法，但是并行的性能问题非常值得我们思考，比方说下面这个例子</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> i = Stream.iterate(<span class="number">1</span>, a -&gt; a + <span class="number">1</span>).limit(<span class="number">100</span>).parallel().reduce(<span class="number">0</span>, Integer::sum);</span><br></pre></td></tr></table></figure>

<p>我们通过这样一行代码来计算 1 到 100 的所有数的和，我们使用了 parallel 来实现并行。</p>
<p>但实际上是，这样的计算，效率是非常低的，比不使用并行还低！一方面是因为装箱问题，还有一方面就是 iterate 方法很难把这些数分成多个独立块来并行执行，因此无形之中降低了效率。</p>
<h3 id="流的可分解性"><a href="#流的可分解性" class="headerlink" title="流的可分解性"></a>流的可分解性</h3><p>使用并行的时候，我们要注意流背后的数据结构是否易于分解。比如众所周知的 ArrayList 和 LinkedList，明显前者在分解方面占优。</p>
<table>
<thead>
<tr>
<th align="left">数据源</th>
<th align="left">可分解性</th>
</tr>
</thead>
<tbody><tr>
<td align="left">ArrayList</td>
<td align="left">极佳</td>
</tr>
<tr>
<td align="left">LinkedList</td>
<td align="left">差</td>
</tr>
<tr>
<td align="left">IntStream.range</td>
<td align="left">极佳</td>
</tr>
<tr>
<td align="left">Stream.iterate</td>
<td align="left">差</td>
</tr>
<tr>
<td align="left">HashSet</td>
<td align="left">好</td>
</tr>
<tr>
<td align="left">TreeSet</td>
<td align="left">好</td>
</tr>
</tbody></table>
<h3 id="顺序性"><a href="#顺序性" class="headerlink" title="顺序性"></a>顺序性</h3><p>除了可分解性，和刚刚提到的装箱问题，还有一点值得注意的是一些操作本身在并行流上的性能就比顺序流要差，比如：limit，findFirst， 因为这两个方法会考虑元素的顺序性，而并行本身就是违背顺序性的，也是因为如此 findAny 一般比 findFirst 的效率要高。</p>

    </div>

    
    
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>yanbing
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://yoursite.com/2020/05/30/Java%E5%9F%BA%E7%A1%80/JavaStream/" title="JavaStream">http://yoursite.com/2020/05/30/Java基础/JavaStream/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/05/30/Java%E5%9F%BA%E7%A1%80/Java%E8%99%9A%E6%8B%9F%E6%9C%BA/" rel="prev" title="Java虚拟机">
      <i class="fa fa-chevron-left"></i> Java虚拟机
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/05/30/Java%E5%9F%BA%E7%A1%80/Java%E5%BC%82%E5%B8%B8/" rel="next" title="Java异常">
      Java异常 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#简介"><span class="nav-number">1.</span> <span class="nav-text">简介</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Stream的概念"><span class="nav-number">2.</span> <span class="nav-text">Stream的概念</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Stream操作的三个步骤"><span class="nav-number">3.</span> <span class="nav-text">Stream操作的三个步骤</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#创建Stream"><span class="nav-number">4.</span> <span class="nav-text">创建Stream</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#常用方法"><span class="nav-number">5.</span> <span class="nav-text">常用方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#filter-T-gt-boolean"><span class="nav-number">5.1.</span> <span class="nav-text">filter(T -&gt; boolean)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#distinct"><span class="nav-number">5.2.</span> <span class="nav-text">distinct()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#sorted-sorted-T-T-gt-int"><span class="nav-number">5.3.</span> <span class="nav-text">sorted() &#x2F; sorted((T, T) -&gt; int)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#limit-long-n"><span class="nav-number">5.4.</span> <span class="nav-text">limit(long n)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#skip-long-n"><span class="nav-number">5.5.</span> <span class="nav-text">skip(long n)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#map-T-gt-R"><span class="nav-number">5.6.</span> <span class="nav-text">map(T -&gt; R)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#flatMap-T-gt-Stream"><span class="nav-number">5.7.</span> <span class="nav-text">flatMap(T -&gt; Stream)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#anyMatch-T-gt-boolean"><span class="nav-number">5.8.</span> <span class="nav-text">anyMatch(T -&gt; boolean)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#allMatch-T-gt-boolean"><span class="nav-number">5.9.</span> <span class="nav-text">allMatch(T -&gt; boolean)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#noneMatch-T-gt-boolean"><span class="nav-number">5.10.</span> <span class="nav-text">noneMatch(T -&gt; boolean)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#findAny-和-findFirst"><span class="nav-number">5.11.</span> <span class="nav-text">findAny() 和 findFirst()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#reduce-T-T-gt-T-和-reduce-T-T-T-gt-T"><span class="nav-number">5.12.</span> <span class="nav-text">reduce((T, T) -&gt; T) 和 reduce(T, (T, T) -&gt; T)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#count"><span class="nav-number">5.13.</span> <span class="nav-text">count()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#collect"><span class="nav-number">5.14.</span> <span class="nav-text">collect()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#forEach"><span class="nav-number">5.15.</span> <span class="nav-text">forEach()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#unordered"><span class="nav-number">5.16.</span> <span class="nav-text">unordered()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数值流"><span class="nav-number">6.</span> <span class="nav-text">数值流</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#流与数值流的转换"><span class="nav-number">6.1.</span> <span class="nav-text">流与数值流的转换</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#流转换为数值流"><span class="nav-number">6.1.1.</span> <span class="nav-text">流转换为数值流</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#数值流转换为流"><span class="nav-number">6.1.2.</span> <span class="nav-text">数值流转换为流</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数值流方法"><span class="nav-number">6.2.</span> <span class="nav-text">数值流方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数值范围"><span class="nav-number">6.3.</span> <span class="nav-text">数值范围</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#汇总"><span class="nav-number">6.4.</span> <span class="nav-text">汇总</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#counting"><span class="nav-number">6.4.1.</span> <span class="nav-text">counting</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#summingInt-summingLong-summingDouble"><span class="nav-number">6.4.2.</span> <span class="nav-text">summingInt, summingLong, summingDouble</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#averagingInt，averagingLong，averagingDouble"><span class="nav-number">6.4.3.</span> <span class="nav-text">averagingInt，averagingLong，averagingDouble</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#summarizingInt，summarizingLong，summarizingDouble"><span class="nav-number">6.4.4.</span> <span class="nav-text">summarizingInt，summarizingLong，summarizingDouble</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#取最值"><span class="nav-number">6.5.</span> <span class="nav-text">取最值</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#joining-连接字符串"><span class="nav-number">6.6.</span> <span class="nav-text">joining 连接字符串</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#groupingBy-分组"><span class="nav-number">6.7.</span> <span class="nav-text">groupingBy 分组</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#partitioningBy-分区"><span class="nav-number">6.8.</span> <span class="nav-text">partitioningBy 分区</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#并行"><span class="nav-number">7.</span> <span class="nav-text">并行</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#流的可分解性"><span class="nav-number">7.1.</span> <span class="nav-text">流的可分解性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#顺序性"><span class="nav-number">7.2.</span> <span class="nav-text">顺序性</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="yanbing"
      src="/images/dog.jpg">
  <p class="site-author-name" itemprop="name">yanbing</p>
  <div class="site-description" itemprop="description">闲看庭前花开落，漫随天外云卷舒。</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">59</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">9</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/yanbingzn" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;yanbingzn" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://blog.csdn.net/i_silence" title="CSDN → https:&#x2F;&#x2F;blog.csdn.net&#x2F;i_silence" rel="noopener" target="_blank"><i class="fab fa-codiepie fa-fw"></i>CSDN</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        
  <div class="beian"><a href="http://www.beian.miit.gov.cn/" rel="noopener" target="_blank">豫ICP备20019377号 </a>
  </div>

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">yanbing</span>
</div>

<span id="busuanzi_container_site_uv">
  本站访问次数：<span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
</span>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script size="300" alpha="0.6" zIndex="-1" src="/lib/canvas-ribbon/canvas-ribbon.js"></script>
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>




  
<script src="/js/local-search.js"></script>













  

  


  
  <script type="text/javascript"
color="0,0,188" opacity='0.5' zIndex="-1" count="120" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>
  

</body>
</html>
